package cn.com.infcn.spider.scheduler.http;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.regex.Pattern;

import org.apache.log4j.Logger;
import org.nlpcn.commons.lang.util.StringUtil;
import org.python.jline.internal.Log;

import cn.com.infcn.spider.URIManager;
import cn.com.infcn.spider.domain.HttpJob;
import cn.com.infcn.spider.domain.Page;
import cn.com.infcn.spider.domain.RegexDomain;
import cn.com.infcn.spider.domain.UrlInfo;
import cn.com.infcn.spider.util.HttpUtils;
import cn.com.infcn.spider.util.JythonRunner;

/**
 * 具体的采集类
 * 
 * @author Ansj
 *
 */
public class HttpWorker implements Runnable {

	private static final Logger LOG = Logger.getLogger(HttpWorker.class);

	private HttpJob job;

	private UrlInfo urlInfo;

	private HttpScheduler scheduler;

	private AtomicInteger atomicInteger;

	private List<RegexDomain> regexList;

	private boolean hasRgex = false; // 是否是正则区域限定

	public HttpWorker(HttpScheduler scheduler, HttpJob job, List<RegexDomain> regexList, UrlInfo url, AtomicInteger atomicInteger) {
		this.job = job;
		this.urlInfo = url;
		this.scheduler = scheduler;
		this.atomicInteger = atomicInteger;
		this.regexList = regexList;

		for (RegexDomain regexDomain : regexList) {
			if (regexDomain.getFlag() == 1) {
				hasRgex = true;
				break;
			}
		}
	}

	@Override
	public void run() {

		try {
			Page page = explan();
			if (page.isOk()) {
				// 增加到列表
				for (String link : page.getAddUrls()) {
					LOG.debug("add " + link + " to linkedList!");
					URIManager.add(job, new UrlInfo(urlInfo, link), false);
				}

				// 打印skip的url
				for (String link : page.getInDbSkipUrls()) {
					LOG.debug("skip " + link + " reason in db!");
				}
				for (String link : page.getRegexSkipUrls()) {
					LOG.debug("skip " + link + " reason regex!");
				}

				// 如果是翻页爬虫,并且翻页不为null
				if (!page.getSkip() && StringUtil.isNotBlank(page.getNextPage())) {
					URIManager.add(job, new UrlInfo(urlInfo, page.getNextPage()), false);
				}

				// 是否保存
				if (!page.getSkipSave()) {
					scheduler.output(page);
				}
			} else {
				LOG.error("gathor err :" + page.getUrl() + "\t" + page.getMessage());
			}

			URIManager.addPage(job, page, urlInfo);

		} catch (Exception e) {
			e.printStackTrace();
			Log.error(e);
		} finally {
			atomicInteger.decrementAndGet();
		}

	}

	public Page explan() {

		RegexDomain regexDomain = findRegexDomain(urlInfo.getUri());

		Page page = null;

		if (regexDomain != null && regexDomain.getGatherType() == 1) {
			page = HttpUtils.getPageByJs(urlInfo.getUri());
		} else {
			page = HttpUtils.getPage(urlInfo.getUri(), job.getTimeout());
		}

		page.setRegexList(regexList);

		if (page.isOk()) {

			Map<String, Object> map = new HashMap<>();

			map.put("_result", page.getResult());

			map.put("_doc", page);

			JythonRunner.run(map, job.getParse());

			// 判断页面类型
			switch (regexDomain.getPageType()) {
			case 1: // 说明是列表页,只抽取url
				page.parseUrls();
				page.setSkipSave(true);
				break;
			case 2: // 说明是内容页
				page.makeNews();
				break;
			default:
				page.makeNews();
				if (job.getParseUrl()) {
					page.parseUrls();
				}
				break;
			}

			for (String link : page.getUrls()) {
				if (regexSkip(findRegexDomain(link))) {
					page.getRegexSkipUrls().add(link);
				} else if (URIManager.checkUrl(job.getName(), link)) {
					page.getInDbSkipUrls().add(link);
				} else {
					page.getAddUrls().add(link);
				}
			}

			if (StringUtil.isNotBlank(page.getNextPage())) {
				page.setSkip(page.getAddUrls().size() == 0);
			}

		}

		return page;
	}

	/**
	 * 找到一个网址的规则
	 * 
	 * @param link
	 * @return
	 */
	private RegexDomain findRegexDomain(String link) {
		for (RegexDomain entry : regexList) {
			if (Pattern.matches(entry.getRegex(), link)) {
				return entry;
			}
		}
		return null;
	}

	/**
	 * 判断一个网址是否可以忽略
	 * 
	 * @param link
	 * @return
	 */
	private boolean regexSkip(RegexDomain regexDomain) {

		if (regexDomain == null && hasRgex) {
			return true;
		}

		switch (regexDomain.getFlag()) {
		case 1:
			return false;
		case 2:
			return true;
		default:
			return false;
		}
	}
}
